home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / ScrollGroup.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  30.1 KB  |  823 lines  |  [TEXT/CWIE]

  1. // ScrollGroup.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp. All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9. /** View subclass that automates the use of a ScrollView
  10.   * and its controlling ScrollBars. You can create a ScrollView and
  11.   * ScrollBars and connect them to each other, or you can create a
  12.   * ScrollGroup that does this work for you. The ScrollGroup places the
  13.   * vertical ScrollBar to the ScrollView's right, and the horizontal
  14.   * ScrollBar below the ScrollView (if configured to have ScrollBars). It draws
  15.   * the specified Border around its ScrollView. If you want to use
  16.   * different ScrollBar positioning, such as different sides of the
  17.   * ScrollView or non-abutting, you can create a ScrollGroup subclass or
  18.   * simply instantiate and position the ScrollView and ScrollBars yourself.
  19.   * @see ScrollBar
  20.   * @see ScrollView
  21.   * @note 1.0 draw->dirtyrect
  22.   * @note 1.0 calc of needing bars using the scrollableObject now
  23.   * @note 1.0 archiving changed
  24.   */
  25.  
  26. public class ScrollGroup extends View implements ScrollBarOwner {
  27.     ScrollView  scrollView;
  28.     ScrollBar   vertScrollBar, horizScrollBar;
  29.     Border      border;
  30.     Border      interiorBorder;
  31.     Color       cornerColor;
  32.     int         horizScrollDisplay, vertScrollDisplay;
  33.     private boolean     ignoreScrollBars;
  34.     private final static boolean debugScrollers = false;
  35.  
  36.     /** Option for the ScrollGroup to never show a ScrollBar.
  37.       */
  38.     public static final int     NEVER_DISPLAY      = 0;
  39.     /** Option for the ScrollGroup to always show a ScrollBar.
  40.       */
  41.     public static final int     ALWAYS_DISPLAY     = 1;
  42.     /** Option for the ScrollGroup to only display a ScrollBar if the
  43.       * contentView does not fit within the ScrollView (i.e. if the ScrollBar
  44.       * is active).
  45.       */
  46.     public static final int     AS_NEEDED_DISPLAY  = 2;
  47.  
  48.     static final String         SCROLLVIEW_KEY = "scrollView",
  49.                                 VERTSCROLLBAR_KEY = "vertScrollBar",
  50.                                 HORIZSCROLLBAR_KEY = "horizScrollBar",
  51.                                 BORDER_KEY = "border",
  52.                                 HORIZDISPLAY_KEY = "horizScrollDisplay",
  53.                                 VERTDISPLAY_KEY = "vertScrollDisplay",
  54.                                 CORNER_COLOR_KEY = "cornerColor";
  55.  
  56.     /** Constructs a ScrollGroup with origin (<B>0</B>, <B>0</B>) and
  57.       * zero width and height.
  58.       */
  59.     public ScrollGroup() {
  60.         this(0, 0, 0, 0);
  61.     }
  62.  
  63.     /** Constructs a ScrollGroup with bounds <B>rect</B>.
  64.       */
  65.     public ScrollGroup(Rect rect) {
  66.         this(rect.x, rect.y, rect.width, rect.height);
  67.     }
  68.  
  69.     /** Constructs a ScrollGroup with bounds
  70.       * (<B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>).
  71.       */
  72.     public ScrollGroup(int x, int y, int width, int height) {
  73.         super(x, y, width, height);
  74.  
  75.         border = EmptyBorder.emptyBorder();
  76.         interiorBorder = new ScrollViewLineBorder();
  77.  
  78.         scrollView = createScrollView();
  79.         addSubview(scrollView);
  80.  
  81.         // We need scrollbars for the putParts to work right
  82.         horizScrollBar = createScrollBar(true);
  83.         horizScrollBar.setScrollableObject(scrollView);
  84.         horizScrollBar.setScrollBarOwner(this);
  85.         scrollView.addScrollBar(horizScrollBar);
  86.         addSubview(horizScrollBar);
  87.  
  88.         vertScrollBar = createScrollBar(false);
  89.         vertScrollBar.setScrollableObject(scrollView);
  90.         vertScrollBar.setScrollBarOwner(this);
  91.         scrollView.addScrollBar(vertScrollBar);
  92.         addSubview(vertScrollBar);
  93.  
  94.         ignoreScrollBars = false;
  95.  
  96.         setCornerColor(Color.lightGray);
  97.  
  98.         layoutView(0, 0);
  99.     }
  100.  
  101.     /** Returns the ScrollGroup's minimum size.  Returns the value set by
  102.       * <b>setMinSize()</b>, or computes the minimum size based on the
  103.       * <b>vertScrollBarDisplay()</b> and <b>horizScrollBarDisplay()</b>
  104.       * settings.
  105.       */
  106.     public Size minSize() {
  107.         Size    minSize;
  108.         int     minWidth = 0, minHeight = 0;
  109.  
  110.         /// If they have set the min Size on the ScrollGroup manually,
  111.         /// ie a non-zero width/height
  112.         /// we should honor the request.
  113.         minSize = super.minSize();
  114.         if (minSize != null && (minSize.width != 0 || minSize.height != 0))
  115.             return minSize;
  116.  
  117.         // Never show either scroller
  118.         if (vertScrollDisplay == NEVER_DISPLAY
  119.             && horizScrollDisplay == NEVER_DISPLAY) {
  120.                 return new Size(border.widthMargin(),
  121.                                 border.heightMargin());
  122.         }
  123.  
  124.         // both scrollers are possibly shown
  125.         if (vertScrollDisplay != NEVER_DISPLAY
  126.             && horizScrollDisplay != NEVER_DISPLAY) {
  127.             return new Size(border.widthMargin()
  128.                                 + horizScrollBar().minSize().width
  129.                                 + vertScrollBar().minSize().width,
  130.                                 border.heightMargin()
  131.                                     + horizScrollBar().minSize().height
  132.                                     + vertScrollBar().minSize().height);
  133.         }
  134.  
  135.         /// If we get here, we are only ever showing one of the scrollers
  136.         if (horizScrollDisplay == ALWAYS_DISPLAY
  137.             || horizScrollDisplay == AS_NEEDED_DISPLAY) {
  138.             return new Size(border.widthMargin()
  139.                                 + horizScrollBar().minSize().width,
  140.                             border.heightMargin()
  141.                                 + horizScrollBar().minSize().height * 2);
  142.         }
  143.  
  144.         if (vertScrollDisplay == ALWAYS_DISPLAY
  145.             || vertScrollDisplay == AS_NEEDED_DISPLAY)  {
  146.             return new Size(border.widthMargin()
  147.                                 + vertScrollBar().minSize().width * 2,
  148.                             border.heightMargin()
  149.                                 + vertScrollBar().minSize().height);
  150.         }
  151.  
  152.         // We should never get here, but to be safe
  153.         return super.minSize();
  154.     }
  155.  
  156.     /** Sets the ScrollGroup's border.
  157.       * This will call <b>layoutView()</b>
  158.       * to make sure the rest of the views get positioned properly.
  159.       * @see Border
  160.       */
  161.     /*
  162.     public void setBorder(Border newBorder) {
  163.         if (newBorder == null)
  164.             newBorder = EmptyBorder.emptyBorder();
  165.  
  166.         border = newBorder;
  167.         layoutView(0,0);
  168.     }
  169.     */
  170.  
  171.     /** Returns the ScrollGroup's border.
  172.       * @see #setBorder
  173.       */
  174.     /*
  175.     public Border border() {
  176.         return border;
  177.     }
  178.     */
  179.  
  180.     /** Overridden to return <b>false</b> unless any of the ScrollGroup's
  181.       * subviews are transparent.
  182.       */
  183.     public boolean isTransparent() {
  184.         Vector sViews;
  185.         int i, count;
  186.  
  187.         sViews = subviews();
  188.         count = sViews.count();
  189.  
  190.         for (i = 0; i < count; i++) {
  191.             if (((View)subviews().elementAt(i)).isTransparent())    {
  192.                 return true;
  193.             }
  194.         }
  195.  
  196.         return false;
  197.     }
  198.  
  199.     /** Sets the ScrollGroup's interior Border, that is, the Border that
  200.       * surrounds the ScrollView.  Calls <b>layoutView()</b>
  201.       * to properly position the ScrollGroup's other Views.
  202.       * @see Border
  203.       */
  204.     public void setBorder(Border newBorder) {
  205.         if (newBorder == null)
  206.             newBorder = EmptyBorder.emptyBorder();
  207.  
  208.         interiorBorder = newBorder;
  209.         layoutView(0,0);
  210.     }
  211.  
  212.     /** Returns the ScrollGroup's interior Border.
  213.       * @see #setInteriorBorder
  214.       */
  215.     public Border border() {
  216.         return interiorBorder;
  217.     }
  218.  
  219.  
  220.     /** Creates a new ScrollView. */
  221.     protected ScrollView createScrollView() {
  222.         return new ScrollView(0, 0, bounds.width, bounds.height);
  223.     }
  224.  
  225.     /** Returns the ScrollGroup's ScrollView. */
  226.     public ScrollView scrollView() {
  227.         return scrollView;
  228.     }
  229.  
  230.     /** Creates a new ScrollBar with the correct orientation. */
  231.     protected ScrollBar createScrollBar(boolean horizontal) {
  232.         ScrollBar aBar;
  233.  
  234.         if (horizontal) {
  235.             aBar = new ScrollBar(0, 0, bounds.width, 1, Scrollable.HORIZONTAL);
  236.         } else {
  237.             aBar = new ScrollBar(0, 0, 1, bounds.height, Scrollable.VERTICAL);
  238.         }
  239.         return aBar;
  240.     }
  241.  
  242.     /** Sets the vertical ScrollBar's behavior. This method exists for backward
  243.       * compatibility.  Equivalent to the following code:
  244.       * <PRE>
  245.       *     if (flag)
  246.       *         setVertScrollBarDisplay(ALWAYS_DISPLAY);
  247.       *     else
  248.       *         setVertScrollBarDisplay(NEVER_DISPLAY);
  249.       * </PRE>
  250.       */
  251.     public void setHasVertScrollBar(boolean flag) {
  252.         if (flag)
  253.             setVertScrollBarDisplay(ALWAYS_DISPLAY);
  254.         else
  255.             setVertScrollBarDisplay(NEVER_DISPLAY);
  256.     }
  257.  
  258.     /** Returns <b>true</b> if the setting for the vertical ScrollBar
  259.       * equals ALWAYS_DISPLAY.
  260.       * @see #vertScrollBarDisplay
  261.       */
  262.     public boolean hasVertScrollBar() {
  263.         return vertScrollDisplay == ALWAYS_DISPLAY;
  264.     }
  265.  
  266.     /** Sets the vertical ScrollBar's behavior.  The ScrollBar can be
  267.       * configured to display when needed, to never display, or to always
  268.       * display. Calls <b>layoutView()</b> to properly position the
  269.       * ScrollGroup's other Views.
  270.       * @see #ALWAYS_DISPLAY
  271.       * @see #NEVER_DISPLAY
  272.       * @see #AS_NEEDED_DISPLAY
  273.       * @see #setHorizScrollBarDisplay
  274.       */
  275.     public void setVertScrollBarDisplay(int flag) {
  276.         vertScrollDisplay = flag;
  277.         if (vertScrollBar == null){
  278.             vertScrollBar = createScrollBar(false);
  279.             vertScrollBar.setScrollableObject(scrollView);
  280.             vertScrollBar.setScrollBarOwner(this);
  281.             scrollView.addScrollBar(vertScrollBar);
  282.             addSubview(vertScrollBar);
  283.         }
  284.         layoutView(0,0);
  285.     }
  286.  
  287.     /** Returns the vertical ScrollBar's behavior setting.
  288.       * @see #setVertScrollBarDisplay
  289.       */
  290.     public int vertScrollBarDisplay()   {
  291.         return vertScrollDisplay;
  292.     }
  293.  
  294.     /** Returns the ScrollGroup's vertical ScrollBar. */
  295.     public ScrollBar vertScrollBar() {
  296.         return vertScrollBar;
  297.     }
  298.  
  299.     /** Sets the horizontal ScrollBar's behavior. This method exists for
  300.       * backward compatibility.  Equivalent to the following code:
  301.       * <PRE>
  302.       *     if (flag)
  303.       *         setHorizScrollBarDisplay(ALWAYS_DISPLAY);
  304.       *     else
  305.       *         setHorizScrollBarDisplay(NEVER_DISPLAY);
  306.       * </PRE>
  307.       */
  308.     public void setHasHorizScrollBar(boolean flag) {
  309.         if (flag)
  310.             setHorizScrollBarDisplay(ALWAYS_DISPLAY);
  311.         else
  312.             setHorizScrollBarDisplay(NEVER_DISPLAY);
  313.     }
  314.  
  315.     /** Returns <b>true</b> if the setting for the horizontal ScrollBar
  316.       * equals ALWAYS_DISPLAY.
  317.       * @see #horizScrollBarDisplay
  318.       */
  319.     public boolean hasHorizScrollBar() {
  320.         return horizScrollDisplay == ALWAYS_DISPLAY;
  321.     }
  322.  
  323.     /** Sets the horizontal ScrollBar's behavior.  The ScrollBar can be
  324.       * configured to display when needed, to never display, or to always
  325.       * display. Calls <b>layoutView()</b> to properly position the
  326.       * ScrollGroup's other Views.
  327.       * @see #ALWAYS_DISPLAY
  328.       * @see #NEVER_DISPLAY
  329.       * @see #AS_NEEDED_DISPLAY
  330.       * @see #setHorizScrollBarDisplay
  331.       */
  332.     public void setHorizScrollBarDisplay(int flag) {
  333.         horizScrollDisplay = flag;
  334.         if (horizScrollBar == null) {
  335.             horizScrollBar = createScrollBar(true);
  336.             horizScrollBar.setScrollableObject(scrollView);
  337.             horizScrollBar.setScrollBarOwner(this);
  338.             scrollView.addScrollBar(horizScrollBar);
  339.             addSubview(horizScrollBar);
  340.         }
  341.         layoutView(0, 0);
  342.     }
  343.  
  344.     /** Returns the horizontal ScrollBar's behavior setting.
  345.       * @see #setHorizScrollBarDisplay
  346.       */
  347.     public int horizScrollBarDisplay()  {
  348.         return horizScrollDisplay;
  349.     }
  350.  
  351.  
  352.     /** Returns the ScrollGroup's horizontal ScrollBar. */
  353.     public ScrollBar horizScrollBar() {
  354.         return horizScrollBar;
  355.     }
  356.  
  357.     /* This guy does the magic of laying out the view.
  358.      * Order is important. Don't move the code around.
  359.      */
  360.     private void putParts() {
  361.         int     sViewX, sViewY, sViewWidth, sViewHeight;
  362.         Rect    contentBounds;
  363.  
  364.         if(debugScrollers)
  365.             System.err.println("  putParts");
  366.  
  367.         // Start from a known state
  368.         horizScrollBar.removeFromSuperview();
  369.         vertScrollBar.removeFromSuperview();
  370.  
  371.         if (scrollView == null)
  372.             return;
  373.  
  374.         contentBounds = new Rect(0, 0, 0, 0);
  375.         if(horizScrollBar != null && horizScrollBar.scrollableObject() != null) {
  376.             contentBounds.width =
  377.                 horizScrollBar.scrollableObject().lengthOfContentViewForAxis(
  378.                                                 Scrollable.HORIZONTAL);
  379.         } else if (scrollView.contentView != null) {
  380.             contentBounds.width = scrollView.contentView.bounds.width;
  381.         }
  382.  
  383.         if(vertScrollBar != null && vertScrollBar.scrollableObject() != null)   {
  384.             contentBounds.height =
  385.                 vertScrollBar.scrollableObject().lengthOfContentViewForAxis(
  386.                                                 Scrollable.VERTICAL);
  387.         } else if (scrollView.contentView != null) {
  388.             contentBounds.height = scrollView.contentView.bounds.height;
  389.         }
  390.  
  391.         if (debugScrollers)
  392.             if (vertScrollBar != null)
  393.                 System.err.println("   vert: " + vertScrollBar.isActive());
  394.         if (debugScrollers)
  395.             if (horizScrollBar != null)
  396.                 System.err.println("   horz: " + horizScrollBar.isActive());
  397.  
  398.  
  399.         sViewX = border.leftMargin() + interiorBorder.leftMargin();
  400.         sViewY = border.topMargin() + interiorBorder.topMargin();
  401.         sViewWidth = bounds.width - border.widthMargin() -
  402.             interiorBorder.widthMargin();
  403.         sViewHeight= bounds.height - border.heightMargin() -
  404.             interiorBorder.heightMargin();
  405.  
  406.         ignoreScrollBars = true;
  407.         scrollView.moveTo(sViewX, sViewY);
  408.         scrollView.sizeTo(sViewWidth, sViewHeight);
  409.         // This is kinda wrong. The scrollView gets sized to the full
  410.         // width, height assuming no bars, but we then put the bars on
  411.         // Since the bars have been removed from the superview, that's
  412.         // ok. The reason we are doing this, is so that the ScrollBars
  413.         // are the right size before we do the calcs. Otherwise, we
  414.         // might be out of sync, because the scrollbar is sized wrong
  415.         // and thinks it is active.
  416.         vertScrollBar.moveTo(sViewX + sViewWidth - vertScrollBar.bounds.width,
  417.                              sViewY);
  418.         vertScrollBar.sizeTo(vertScrollBar.bounds.width, sViewHeight);
  419.         horizScrollBar.moveTo(sViewX, sViewY + sViewHeight -
  420.                               horizScrollBar.bounds.height);
  421.         horizScrollBar.sizeTo(sViewWidth, horizScrollBar.bounds.height);
  422.         ignoreScrollBars = false;
  423.  
  424.         /// Need both scrollbars
  425.         if ((vertScrollDisplay == ALWAYS_DISPLAY
  426.              && horizScrollDisplay == ALWAYS_DISPLAY)
  427.             || ((vertScrollDisplay == AS_NEEDED_DISPLAY
  428.                  && horizScrollDisplay == AS_NEEDED_DISPLAY)
  429.                     && (scrollView.bounds.width <
  430.                             contentBounds.width
  431.                     && scrollView.bounds.height <
  432.                             contentBounds.height)))  {
  433.             setBothScrollersOn();
  434.             return;
  435.         }
  436.  
  437.         // Need Vert scrollbars
  438.         if ((vertScrollDisplay == ALWAYS_DISPLAY)
  439.                 || (vertScrollDisplay == AS_NEEDED_DISPLAY
  440.                     && scrollView.bounds.height <
  441.                         contentBounds.height))    {
  442.             // By adding the Vertical do we also need the horizontal?
  443.             if (debugScrollers)
  444.                 System.err.println("  " + (scrollView.bounds.width
  445.                                          - contentBounds.width)
  446.                                          + " < " + vertScrollBar.bounds.width);
  447.             if ((horizScrollDisplay == ALWAYS_DISPLAY)
  448.                 || (horizScrollDisplay == AS_NEEDED_DISPLAY
  449.                     && ((scrollView.bounds.width - contentBounds.width)
  450.                         < vertScrollBar.bounds.width))) {
  451.                 if(debugScrollers)
  452.                     System.err.println("because of vert");
  453.                 setBothScrollersOn();
  454.                 return;
  455.             }
  456.  
  457.             horizScrollBar.removeFromSuperview();
  458.  
  459.             ignoreScrollBars = true;
  460.             scrollView.moveTo(sViewX, sViewY);
  461.             scrollView.sizeTo(sViewWidth - vertScrollBar.bounds.width,
  462.                               sViewHeight);
  463.             vertScrollBar.moveTo(bounds.width - border.rightMargin() -
  464.                                  vertScrollBar.bounds.width,
  465.                                  border.topMargin());
  466.             vertScrollBar.sizeTo(vertScrollBar.bounds.width, bounds.height -
  467.                                  border.heightMargin());
  468.             addSubview(vertScrollBar);
  469.             ignoreScrollBars = false;
  470.  
  471.             if (debugScrollers)
  472.                 System.err.println(" Vert");
  473.             return;
  474.         }
  475.  
  476.         // Inactive Scrollbar - need to remove it and adjust the scrollview
  477.         // Really this means that we don't need either scroller. Make it so.
  478.         if ((vertScrollDisplay == AS_NEEDED_DISPLAY
  479.              && horizScrollDisplay == AS_NEEDED_DISPLAY)
  480.                  && (scrollView.bounds.height == contentBounds.height)) {
  481.             ignoreScrollBars = true;
  482.             vertScrollBar.removeFromSuperview();
  483.             horizScrollBar.removeFromSuperview();
  484.             scrollView.moveTo(sViewX, sViewY);
  485.             scrollView.sizeTo(sViewWidth, sViewHeight);
  486.             ignoreScrollBars = false;
  487.             if (debugScrollers)
  488.                 System.err.println(" vert == Removed");
  489.             return;
  490.         }
  491.  
  492.         /// Need horiz scrollbars
  493.         if ((horizScrollDisplay == ALWAYS_DISPLAY)
  494.                 || (horizScrollDisplay == AS_NEEDED_DISPLAY
  495.                     && scrollView.bounds.width < contentBounds.width)) {
  496.             // By adding the Horizontal do we also need the vertical?
  497.             if((vertScrollDisplay == ALWAYS_DISPLAY)
  498.                 || (vertScrollDisplay == AS_NEEDED_DISPLAY
  499.                     && scrollView.bounds.height - contentBounds.height <
  500.                             horizScrollBar.bounds.height)) {
  501.                 if (debugScrollers)
  502.                     System.err.println("because of horiz");
  503.                 setBothScrollersOn();
  504.                 return;
  505.             }
  506.  
  507.             vertScrollBar.removeFromSuperview();
  508.  
  509.             ignoreScrollBars = true;
  510.             scrollView.moveTo(sViewX, sViewY);
  511.             scrollView.sizeTo(sViewWidth,
  512.                               sViewHeight - horizScrollBar.bounds.height);
  513.             horizScrollBar.moveTo(border.leftMargin(),
  514.                                   bounds.height - border.bottomMargin() -
  515.                                   horizScrollBar.bounds.height);
  516.             horizScrollBar.sizeTo(bounds.width - border.widthMargin(),
  517.                                   horizScrollBar.bounds.height);
  518.             addSubview(horizScrollBar);
  519.             ignoreScrollBars = false;
  520.  
  521.             if (debugScrollers)
  522.                 System.err.println(" Horiz " );
  523.             return;
  524.         }
  525.  
  526.         // Inactive Scrollbar - need to remove it and adjust the scrollview
  527.         // Really this means that we don't need either scroller. Make it so.
  528.         if ((horizScrollDisplay == AS_NEEDED_DISPLAY
  529.             && vertScrollDisplay == AS_NEEDED_DISPLAY)
  530.             && (scrollView.bounds.width == contentBounds.width)) {
  531.             ignoreScrollBars = true;
  532.             horizScrollBar.removeFromSuperview();
  533.             vertScrollBar.removeFromSuperview();
  534.             scrollView.moveTo(sViewX, sViewY);
  535.             scrollView.sizeTo(sViewWidth, sViewHeight);
  536.             ignoreScrollBars = false;
  537.             if (debugScrollers)
  538.                 System.err.println(" Horiz == Removed");
  539.             return;
  540.         }
  541.  
  542.         if (debugScrollers)
  543.             System.err.println(" Fall through case - None ");
  544.  
  545. //        if(debugScrollers) System.err.println(" ALMOST MISSED A CASE " +
  546. //                                "Inconsistancy Error " +
  547. //                                            "\n - " + scrollView +
  548. //                                            "\n - " + scrollView.contentView +
  549. //                                            "\n - " + this);
  550. //
  551. //          if(debugScrollers)
  552. //          System.err.println("    H:" + scrollView.bounds.height + " , "
  553. //                                                                                              + contentBounds.height
  554. //                                                                                              + vertScrollBar);
  555. //        if(debugScrollers)
  556. //          System.err.println("    W:" + scrollView.bounds.width + " , "
  557. //                                                                                              + contentBounds.width
  558. //                                                                                              + horizScrollBar);
  559.     }
  560.  
  561.     void setBothScrollersOn()   {
  562.         int     sViewX, sViewY, sViewWidth, sViewHeight;
  563.  
  564.         sViewX = border.leftMargin() + interiorBorder.leftMargin();
  565.         sViewY = border.topMargin() + interiorBorder.topMargin();
  566.         sViewWidth  = bounds.width - border.widthMargin() -
  567.             interiorBorder.widthMargin();
  568.         sViewHeight = bounds.height - border.heightMargin() -
  569.             interiorBorder.heightMargin();
  570.  
  571.         ignoreScrollBars = true;
  572.  
  573.         scrollView.moveTo(sViewX, sViewY);
  574.         scrollView.sizeTo(sViewWidth - vertScrollBar.bounds.width,
  575.                           sViewHeight - horizScrollBar.bounds.height);
  576.         horizScrollBar.moveTo(border.leftMargin(),
  577.                               bounds.height - border.bottomMargin() -
  578.                               horizScrollBar.bounds.height);
  579.         horizScrollBar.sizeTo(bounds.width - border.widthMargin() -
  580.                               vertScrollBar.bounds.width + 2,
  581.                               horizScrollBar.bounds.height);
  582.         addSubview(horizScrollBar);
  583.  
  584.         vertScrollBar.moveTo(bounds.width - border.rightMargin() -
  585.                              vertScrollBar.bounds.width, border.topMargin());
  586.         vertScrollBar.sizeTo(vertScrollBar.bounds.width,
  587.                              bounds.height - border.heightMargin() -
  588.                              horizScrollBar.bounds.height + 2);
  589.         addSubview(vertScrollBar);
  590.  
  591.         ignoreScrollBars = false;
  592.  
  593.         if (debugScrollers)
  594.             System.err.println(" Both");
  595.     }
  596.  
  597.     /** Draws the ScrollGroup's interior Border. */
  598.     public void drawView(Graphics g) {
  599.         border.drawInRect(g, 0, 0,  bounds.width, bounds.height);
  600.         interiorBorder.drawInRect(g, border.leftMargin(), border.topMargin(),
  601.                scrollView.bounds.width + interiorBorder.widthMargin(),
  602.                scrollView.bounds.height + interiorBorder.heightMargin());
  603.         if (cornerColor != null && horizScrollBarIsVisible() &&
  604.                vertScrollBarIsVisible()) {
  605.             g.setColor(cornerColor);
  606.             g.fillRect(horizScrollBar.bounds.maxX(),
  607.                        vertScrollBar.bounds.maxY(),
  608.                        vertScrollBar.bounds.width - 2,
  609.                        horizScrollBar.bounds.height - 2);
  610.         }
  611.     }
  612.  
  613.     /** Draws the ScrollView portion of the ScrollGroup. */
  614.     public void drawContents() {
  615.         scrollView.setDirty(true);
  616.     }
  617.  
  618.     /** @private */
  619.     public void drawSubviews(Graphics g) {
  620.         super.drawSubviews(g);
  621.         drawView(g);
  622.     }
  623.  
  624.     /** Convenience method for making <b>aView</b> the ScrollView's content
  625.       * View.  Calls <b>layoutView()</b> to properly position the
  626.       * ScrollGroup's other Views.
  627.       * @see ScrollView#setContentView
  628.       */
  629.     public void setContentView(View aView) {
  630.         scrollView.setContentView(aView);
  631.         layoutView(0, 0);
  632.     }
  633.  
  634.     /** Convenience method for retrieving the ScrollGroup's ScrollView's
  635.       * contentView.
  636.       * @see ScrollView#contentView
  637.       */
  638.     public View contentView() {
  639.         return scrollView.contentView();
  640.     }
  641.  
  642.     /** Convenience method for setting the ScrollGroup's ScrollView's
  643.       * background Color.
  644.       * @see ScrollView#setBackgroundColor
  645.       */
  646.     public void setBackgroundColor(Color aColor) {
  647.         scrollView.setBackgroundColor(aColor);
  648.     }
  649.  
  650.     /** Sets the color displayed in the bottom right corner of the
  651.       * ScrollGroup when both a horizontal Scrollbar and vertical ScrollBar
  652.       * are visible.
  653.       * @private
  654.       */
  655.     public void setCornerColor(Color aColor) {
  656.         cornerColor = aColor;
  657.     }
  658.  
  659. /* archiving */
  660.  
  661.     /** Describes the ScrollGroup class' information.
  662.       * @see Codable#describeClassInfo
  663.       */
  664.     public void describeClassInfo(ClassInfo info) {
  665.         super.describeClassInfo(info);
  666.  
  667.         info.addClass("netscape.application.ScrollGroup", 2);
  668.         info.addField(SCROLLVIEW_KEY, OBJECT_TYPE);
  669.         info.addField(VERTSCROLLBAR_KEY, OBJECT_TYPE);
  670.         info.addField(HORIZSCROLLBAR_KEY, OBJECT_TYPE);
  671.         info.addField(BORDER_KEY, OBJECT_TYPE);
  672.         info.addField(HORIZDISPLAY_KEY, INT_TYPE);
  673.         info.addField(VERTDISPLAY_KEY, INT_TYPE);
  674.         info.addField(CORNER_COLOR_KEY, OBJECT_TYPE);
  675.     }
  676.  
  677.     /** Encodes the ScrollGroup instance.
  678.       * @see Codable#encode
  679.       */
  680.     public void encode(Encoder encoder) throws CodingException {
  681.         super.encode(encoder);
  682.  
  683.         encoder.encodeObject(SCROLLVIEW_KEY, scrollView);
  684.         encoder.encodeObject(VERTSCROLLBAR_KEY, vertScrollBar);
  685.         encoder.encodeObject(HORIZSCROLLBAR_KEY, horizScrollBar);
  686.         encoder.encodeObject(BORDER_KEY, interiorBorder);
  687.         encoder.encodeInt(HORIZDISPLAY_KEY, horizScrollDisplay);
  688.         encoder.encodeInt(VERTDISPLAY_KEY, vertScrollDisplay);
  689.         encoder.encodeObject(CORNER_COLOR_KEY, cornerColor);
  690.     }
  691.  
  692.     /** Decodes the ScrollGroup instance.
  693.       * @see Codable#decode
  694.       */
  695.     public void decode(Decoder decoder) throws CodingException {
  696.         int version = decoder.versionForClassName("netscape.application.ScrollGroup");
  697.         super.decode(decoder);
  698.  
  699.         scrollView = (ScrollView)decoder.decodeObject(SCROLLVIEW_KEY);
  700.         vertScrollBar = (ScrollBar)decoder.decodeObject(VERTSCROLLBAR_KEY);
  701.         horizScrollBar = (ScrollBar)decoder.decodeObject(HORIZSCROLLBAR_KEY);
  702.         interiorBorder = (Border)decoder.decodeObject(BORDER_KEY);
  703.         horizScrollDisplay = (int)decoder.decodeInt(HORIZDISPLAY_KEY);
  704.         vertScrollDisplay = (int)decoder.decodeInt(VERTDISPLAY_KEY);
  705.         if(version >= 2)
  706.             cornerColor = (Color)decoder.decodeObject(CORNER_COLOR_KEY);
  707.         else
  708.             cornerColor = Color.lightGray;
  709.     }
  710.  
  711.     /* ScrollBarOwner */
  712.  
  713.     /** Implemented to catch ScrollBar activation and ensure their proper
  714.       * display.
  715.       * @see ScrollBarOwner
  716.       */
  717.     public void scrollBarDidBecomeActive(ScrollBar aScrollBar)    {
  718.         if(debugScrollers)
  719.             System.err.println("--scrollBarBecameActive");
  720.  
  721.         if(ignoreScrollBars)
  722.             return;
  723.         if(aScrollBar == horizScrollBar && horizScrollDisplay == NEVER_DISPLAY)
  724.             return;
  725.         if(aScrollBar == vertScrollBar && vertScrollDisplay == NEVER_DISPLAY)
  726.             return;
  727.  
  728.         layoutView(0, 0);
  729.         if(debugScrollers)  {
  730.             if(aScrollBar == vertScrollBar && !vertScrollBarIsVisible())
  731.                 System.err.println("Inconsistancy Error " + aScrollBar +
  732.                     " - " + scrollView +
  733.                     " - " + scrollView.contentView +
  734.                     " - " + this);
  735.             else if(aScrollBar == horizScrollBar && !horizScrollBarIsVisible())
  736.                 System.err.println("Inconsistancy Error " + aScrollBar +
  737.                     "\n - " + scrollView +
  738.                     "\n - " + scrollView.contentView +
  739.                     "\n - " + this);
  740.         }
  741.    }
  742.  
  743.     /** Implemented to catch ScrollBar deactivation and ensure their removal,
  744.       * if necessary.
  745.       * @see ScrollBarOwner
  746.       */
  747.     public void scrollBarDidBecomeInactive(ScrollBar aScrollBar)  {
  748.         if(debugScrollers)
  749.             System.err.println("--scrollBarBecameInactive");
  750.  
  751.         if(ignoreScrollBars)
  752.             return;
  753.         if(aScrollBar == horizScrollBar && horizScrollDisplay == NEVER_DISPLAY)
  754.             return;
  755.         if(aScrollBar == vertScrollBar && vertScrollDisplay == NEVER_DISPLAY)
  756.             return;
  757.  
  758.         layoutView(0, 0);
  759.     }
  760.  
  761.     /** Implemented to catch ScrollBar enabling and ensure their display.
  762.       * @see ScrollBarOwner
  763.       */
  764.     public void scrollBarWasEnabled(ScrollBar aScrollBar) {
  765.         if(debugScrollers)
  766.             System.err.println("--scrollBarEnabled");
  767.  
  768.         if(ignoreScrollBars)
  769.             return;
  770.         if(aScrollBar == horizScrollBar && horizScrollDisplay == NEVER_DISPLAY)
  771.             return;
  772.         if(aScrollBar == vertScrollBar && vertScrollDisplay == NEVER_DISPLAY)
  773.             return;
  774.  
  775.         layoutView(0, 0);
  776.     }
  777.  
  778.     /** Implemented to catch ScrollBar disabling and ensure their removal,
  779.       * if necessary.
  780.       * @see ScrollBarOwner
  781.       */
  782.     public void scrollBarWasDisabled(ScrollBar aScrollBar)    {
  783.         if(debugScrollers)
  784.             System.err.println("--scrollBarDisabled");
  785.  
  786.         if(ignoreScrollBars)
  787.             return;
  788.         if(aScrollBar == horizScrollBar && horizScrollDisplay == NEVER_DISPLAY)
  789.             return;
  790.         if(aScrollBar == vertScrollBar && vertScrollDisplay == NEVER_DISPLAY)
  791.             return;
  792.  
  793.         layoutView(0, 0);
  794.     }
  795.  
  796.     /** Returns <b>true</b> if the vertical ScrollBar is visible. Equivalent to
  797.       * <PRE>
  798.       *     return vertScrollBar().isInViewHierarchy();
  799.       * </PRE>
  800.       */
  801.     public boolean vertScrollBarIsVisible() {
  802.         return vertScrollBar.isInViewHierarchy();
  803.     }
  804.  
  805.     /** Returns <b>true</b> if the horizontal ScrollBar is visible. Equivalent
  806.       * to
  807.       * <PRE>
  808.       *     return horizScrollBar().isInViewHierarchy();
  809.       * </PRE>
  810.       */
  811.     public boolean horizScrollBarIsVisible() {
  812.         return horizScrollBar.isInViewHierarchy();
  813.     }
  814.  
  815.     /** Overridden to implement special ScrollGroup subview layout behavior.
  816.       */
  817.     public void layoutView(int x, int y)    {
  818.         putParts();
  819.         ignoreScrollBars = false;   // We shouldn't need this, but just in case
  820.         setDirty(true);
  821.     }
  822. }
  823.